package pl.smath.regex.tree;

import java.util.List;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import pl.smath.regex.exceptions.ParseError;
import pl.smath.regex.tree.vertexes.ConstVertex;

public class Tape extends Vector<Token> {

	/**
	 * Tape on which given expression is stored and recognized.
	 */
	
	private static final long serialVersionUID = 1L;
	
	public Tape() {
		super();
	}
	
	public Tape(Token t) {
		super();
		this.add(t);
	}
	
	public Tape(List<Token> subList) {
		super();
		this.addAll(subList);
	}

	public void change(int pos, Tape paste) {
		this.remove(pos);
		this.addAll(pos, paste);
	}
	
	public void change(int from, int to, Tape paste) {
		this.removeRange(from, to);
		this.addAll(from, paste);
	}
	
	public void change(int pos, Token paste) {
		this.remove(pos);
		this.add(pos, paste);
	}
	
	public void change(int from, int to, Token paste) {
		this.removeRange(from, to);
		this.add(from, paste);
	}
	
	
	
	public TapePosition indexOf(String find) {
		for (int i=0; i<size(); i++) {
			Token token = elementAt(i);
			if (token.isString()) {
				String part = token.toString();
				int pos = part.indexOf(find);
				if (pos != -1) return new TapePosition(i, pos);
			}
		}
		return new TapePosition(-1);
	}
	
	public TapePosition indexOf(String find, TapePosition index) {
		if (index.notFound())
			return new TapePosition(-1);
		
		Token token = elementAt(index.getFirst());
		if (token.isString()) {
			String part = token.toString();
			int pos = part.indexOf(find, index.getSecond());
			if (pos != -1) return new TapePosition(index.getFirst(), pos);
		}
		
		for (int i=index.getFirst()+1; i<size(); i++) {
			token = elementAt(i);
			if (token.isString()) {
				String part = token.toString();
				int pos = part.indexOf(find);
				if (pos != -1) return new TapePosition(i, pos);
			}
		}
		return new TapePosition(-1);
	}
	
	public TapePosition lastIndexOf(String find, TapePosition index) {
		if (index.notFound())
			return new TapePosition(-1);
		
		Token token = elementAt(index.getFirst());
		if (token.isString()) {
			String part = token.toString();
			int pos = part.lastIndexOf(find, index.getSecond());
			if (pos != -1) return new TapePosition(index.getFirst(), pos);
		}
		
		for (int i=index.getFirst()-1; i>=0; i--) {
			token = elementAt(i);
			if (token.isString()) {
				String part = token.toString();
				int pos = part.lastIndexOf(find);
				if (pos != -1) return new TapePosition(i, pos);
			}
		}
		return new TapePosition(-1);
	}


	
	public int splitAt(TapePosition pos) {
		if (pos.getSecond()<0)
			return pos.getFirst()-1;
		
		Tape paste = new Tape();
		int inc = 0;
		
		String part = elementAt(pos.getFirst()).toString().substring(0, pos.getSecond());
		if (part.length()>0) {
			paste.add(new Token(part));
			inc = 1;
		}
		
		part = elementAt(pos.getFirst()).toString().substring(pos.getSecond());
		if (part.length()>0) 
			paste.add(new Token(part));
		else
			inc--;
		
		this.change(pos.getFirst(), paste);
		return pos.getFirst() + inc;
	}

	public boolean delete(TapePosition index) {
		String change = elementAt(index.getFirst()).toString();
		change = change.substring(0, index.getSecond()) + change.substring(index.getSecond()+1);
		if (change.length() == 0) {
			this.remove(index.getFirst());
			return true;
		} else {
			this.change(index.getFirst(), new Token(change));
			return false;
		}
	}

	public void convertConst() throws ParseError {
		for (int i=0; i<size(); i++) {
			Token token = elementAt(i);
			if (token.isString()) {
				String part = token.toString();
				Pattern p = Pattern.compile("\\d+");
		        Matcher m = p.matcher(part);
		        while(m.find()) {
		        	int inc = 0;
		            ConstVertex constant = new ConstVertex(m.group());
		            String prefix = part.substring(0, m.start());
		            String sufix = part.substring(m.end());
		            Tape paste = new Tape();
		            if (prefix.length() > 0) {
		            	paste.add(new Token(prefix));
		            	inc++;
		            } 
		           	paste.add(new Token(constant));
		            if (sufix.length() > 0) {
		            	paste.add(new Token(sufix));
		        		inc++;
	            	} 
		            this.change(i, paste);
		            i += inc;
		            
		        	part = sufix;		            
		            m = p.matcher(part);
		        } 
			}
		}
		
	}

}
